using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Threading;
using AsyncLibrary.Internal;
using log4net.Config;

namespace AsyncLibrary
{
  /// <summary>Represents Thread from unrestricted internal ThreadPool 
  ///   equipped with it's own Operations Queue.</summary>
  /// <remarks>
  ///   <para><see cref="VirtualThread"/> instance has got 
  ///   <see cref="SynchronizationContext"/> associated with it. It's current
  ///   context of the thread VirtualThread ctor is called on.</para>
  ///   <para>We couldn't use system <see cref="ThreadPool"/> as it 
  ///   is one queue + many threads. We need one queue + one thread.</para>
  ///   <para>Support <see cref="IComponent"/> to make it easier to use
  ///   <see cref="VirtualThread"/> with controls</para>
  /// </remarks> 
  public class VirtualThread : IComponent
  {
    private OperationCore _core;
    private static readonly Queue<OperationCore>
      Pool = new Queue<OperationCore>();

    /// <summary>Creates instance of <see cref="VirtualThread"/>, associates
    ///   it with <see cref="Thread"/> from the pool, operations queue,
    ///   and calling thread's <see cref="SynchronizationContext"/></summary>
    public VirtualThread()
      : this(SynchronizationContext.Current, "Virtual Thread")
    { }

    /// <summary>Creates instance of <see cref="VirtualThread"/>, associates
    ///   it with <see cref="Thread"/> from the pool, operations queue,
    ///   and calling thread's <see cref="SynchronizationContext"/></summary>
    public VirtualThread(string name)
      : this(SynchronizationContext.Current, name)
    { }

    /// <summary>Creates instance of <see cref="VirtualThread"/> with
    ///   specified <see cref="SynchronizationContext"/>.</summary>
    public VirtualThread(SynchronizationContext context, string name)
    {
//      ConfigureLog();

      lock (Pool)
        if (Pool.Count > 0)
          _core = Pool.Dequeue();

      if (_core == null)
        _core = new OperationCore(name);

      _core.SyncContext = context;
      Debug.Assert(_core.SyncContext != null);
    }

    private static void ConfigureLog()
    {
      var dllPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
      var configPath = dllPath + ".config";
      if (File.Exists(configPath))
        XmlConfigurator.Configure(new FileInfo(configPath));
    }

    /// <summary>Add work item into the queue of operations
    ///   waiting CPU time to be executed</summary>
    /// <param name="op"></param>
    public void QueueOperation(IOperation op)
    {
      _core.QueueWorkItem(op);
    }
    /// <summary>Returns <see cref="Thread"/> into back pool </summary>
    public void Dispose()
    {
      _core.ClearQueue();
      lock (Pool)
        Pool.Enqueue(_core);
      _core = null;
    }

    #region ' IComponent Members '

    public event EventHandler Disposed
    {
      add { throw new NotImplementedException(); }
      remove { throw new NotImplementedException(); }
    }

    ISite IComponent.Site
    {
      get { return null; /*don't need it*/ }
      set {  }
    }

    #endregion
  }
}
